package com.xc.stock.aop.distributedlock;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.xc.stock.aop.annotation.DistributedLock;

import lombok.extern.slf4j.Slf4j;

@Aspect
@Component("CommonDistributedLockAspect")
@Slf4j
@Order(-1000)
public class DistributedLockAspect {

	@Autowired(required = false)
	private DistributedLockTemplate lockTemplate;

	@Pointcut("@annotation(com.xc.stock.aop.annotation.DistributedLock)")
	public void distributedLockAspect() {
	}

	@Around(value = "distributedLockAspect()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		MethodSignature ms = ((MethodSignature) pjp.getSignature());
		Method method = ms.getMethod();
		DistributedLockCallback<Object> callback = new DistributedLockCallback<Object>() {
			@Override
			public Object process() throws Throwable {
				return proceed(pjp);
			}
		};
		
		return lockTemplate.lock(callback, DistributedLockInfo.build(method.getAnnotation(DistributedLock.class), pjp.getArgs()));
	}

	@AfterThrowing(value = "distributedLockAspect()", throwing = "throwable")
	public void afterThrowing(Throwable throwable) throws Throwable {
		log.info(String.format("抛出异常失败:%s", throwable.getLocalizedMessage()));
		throwable.printStackTrace();
		throw throwable;
	}

	public Object proceed(ProceedingJoinPoint pjp) throws Throwable {
		try {
			return pjp.proceed();
		} catch (Throwable throwable) {
			log.info(String.format("抛出异常失败:%s", throwable.getLocalizedMessage()));
			throwable.printStackTrace();
			throw throwable;
		}
	}
}
